home *** CD-ROM | disk | FTP | other *** search
- Program HashTable;
-
- { *************************************************************************** }
- { * * }
- { * CHAIN BUCKET HASHING PROGRAM * }
- { * Program #3 * }
- { * * }
- { * Class: CS 367 Section: 4 * }
- { * Instructor: Wiegand * }
- { * * }
- { * Written by Chris Maeder * }
- { * Edited and Compiled using Turbo Pascal * }
- { * on an IBM PC * }
- { * * }
- { * DEFINITION: * }
- { * A hash table is a data structure that does not require * }
- { * none if any searching to find a piece of data. Rather, it * }
- { * provides an efficient means of readily accessing a piece of * }
- { * data. * }
- { * * }
- { * ALGORITHM: * }
- { * A hash function is applied to part or all of a given piece of * }
- { * data ( see Function HashValue ). From the hash function a key * }
- { * or hash value is determines which describes where the data * }
- { * should be placed in the hash table. If there is already a * }
- { * piece of data at that particular hash value then a collision * }
- { * occurs, that is to say two pieces of data hashing to the same * }
- { * hash value. * }
- { * * }
- { * Chain bucket hashing circumnavigates this collision problem * }
- { * by constructing a linked list tied to each element of the * }
- { * hash table. When a collision occurs then the data elements * }
- { * that have hashed to the same hash value are inserted into the * }
- { * linked list maintaining their sorted ascending order. An * }
- { * example can be seen below: * }
- { * * }
- { * HASH TABLE * }
- { * (an array of pointers) * }
- { * _______ * }
- { * 0. | Nil | * }
- { * |_______| _______ _______ _______ * }
- { * 1. | |____>| Data |____>| Data |____>| Nil | * }
- { * |_______| |_______| |_______| |_______| * }
- { * 2. | Nil | * }
- { * |_______| ^Linked List * }
- { * | Nil | * }
- { * ___| * }
- { * * }
- { * . * }
- { * . * }
- { * . * }
- { * * }
- { * |_____ * }
- { * | Nil | * }
- { * |_______| * }
- { * 11. | Nil | * }
- { * |_______| * }
- { * 12. | Nil | * }
- { * |_______| * }
- { * * }
- { * * }
- { * PURPOSE: * }
- { * 1. Print program heading. * }
- { * 2. Provide a means of storing, maintaining, and retrieving * }
- { * information about Madison friends/family/business * }
- { * associates through the use of a hash table. * }
- { * 3. Use chain hashing to handle collisions. * }
- { * 4. Maintain each chained linked list in sorted order to * }
- { * facilitate searching. * }
- { * 5. Be able to: * }
- { * a. Insert a data entry into the data set. * }
- { * b. Delete a data entry from the data set. * }
- { * c. Search for a data entry in the data set. * }
- { * * }
- { * INPUT/OUTPUT: * }
- { * 1. Print program heading. * }
- { * 2. The program reads the data entry out of the data file. * }
- { * a. Echo print the read file entry. * }
- { * 3. Pass control to the proper data handling procedure. * }
- { * a. Insert a data entry into the data set. * }
- { * i. Print a message stating what is about to be done. * }
- { * ii. Echo print out entry with labels. * }
- { * iii. Reply that the data entry was placed into the data * }
- { * set. * }
- { * b. Delete a data entry from the data set. * }
- { * i. Print a message stating what is about to be done. * }
- { * ii. Echo print the file entry with labels. * }
- { * iii. Reply that the data entry was deleted from the data * }
- { * set if found otherwise reply that the data entry * }
- { * was not found. * }
- { * c. Search for a data entry in the data set. * }
- { * i. Print a message stating what is about to be done. * }
- { * ii. Echo print the file entry with labels. * }
- { * iii. Print out the contents of the data entry if found * }
- { * otherwise reply that the data entry was not found. * }
- { * d. Print that a bad command was entered if the command * }
- { * entered is not of the type allowed. * }
- { * 4. After reading the data file and doing the proper operations * }
- { * on the data. * }
- { * i. Print out the hash table and its contents. * }
- { * ii. Halt the program. * }
- { * * }
- { *************************************************************************** }
-
- Const
- MAX_TABLE_SIZE=12; { maximum size of the hash table+1 }
- MAX_NAME_SIZE=16; { maximum size of the name entry }
- MAX_BIRTHDATE_SIZE=5; { maximum size of the birthdate entry }
- MAX_ADDRESS_SIZE=25; { maximum size of the address entry }
- MAX_FILE_ENTRY_SIZE=55; { maximum size of the file entry }
- FILE_NAME='Hash.Fil';
- L_PRINT=False; { a boolean used to control the re-direction of the output to the printer }
-
- Type
- NameString=String[MAX_NAME_SIZE]; { a string type used to store name entries }
- BirthdateString=String[MAX_BIRTHDATE_SIZE]; { a string type used to store birthdate entries }
- AddressString=String[MAX_ADDRESS_SIZE]; { a string type used to store address entries }
- FileEntryString=String[MAX_FILE_ENTRY_SIZE];
- TextString=String[MAX_FILE_ENTRY_SIZE];
-
- Ptr=^Person; { a pointer which points to the data record type 'Person' }
- Person= { a data record type used to store information }
- Record
- Name:NameString;
- Birthdate:BirthdateString;
- Address:AddressString;
- Next:Ptr;
- End; { Person }
-
- IndexType=1..MAX_TABLE_SIZE;
-
- Var
- HashPtrTable:Array[0..MAX_TABLE_SIZE] Of Ptr; { an array of pointers which point to the data record type Person }
- HoldPtr:Integer; { a temporary pointer used in re-directing the output from the screen
- to the printer }
-
-
-
- Procedure PrintHeading;
-
- { This procedure prints a heading for the program. }
-
- Begin { PrintHeading }
- WriteLn;
- WriteLn('CHAIN BUCKET HASHING DEMONSTRATION PROGRAM');
- WriteLn;
- End; { PrintHeading }
-
-
-
- Procedure InitHashTable;
-
- { This procedure initializes the pointers in the pointer array HashPtrTable to
- Nil. }
-
- Var
- Index:IndexType;
-
- Begin { InitHashTable }
- For Index:=0 To MAX_TABLE_SIZE Do
- HashPtrTable[Index]:=Nil;
- End; { InitHashTable }
-
-
-
- Procedure RemoveFirstEntryFromString(Var Text:TextString);
-
- { This procedure removes the first text entry from the passed text string and
- returns the new truncated text string. The text entries in the passed text
- string are assumed to be delinated by one space. See the following
- example.
-
- Passed: Entry1 Entry2 Entry3
- Returned: Entry2 Entry3 }
-
- Begin { RemoveFirstEntryFromString }
- If Pos(' ',Text)<>0 Then
- Text:=Copy(Text,(Pos(' ',Text)+1),(Length(Text)-Pos(' ',Text)));
- End; { RemoveFirstEntryFromString }
-
-
-
- Procedure ReturnFirstEntryFromString(Var Text:TextString);
-
- { This procedure removes the first text entry from the passed text string and
- returns the first text entry. The text entries in the passed text string
- are assumed to be delinated by one space. See the following example.
-
- Passed: Entry1 Entry2 Entry3
- Returned: Entry1 }
-
- Begin { ReturnFirstEntryFromString }
- If Pos(' ',Text)<>0 Then
- Text:=Copy(Text,1,(Pos(' ',Text)-1));
- End; { ReturnFirstEntryFromString }
-
-
-
- Function Command(Entry:FileEntryString):FileEntryString;
-
- { This function is passed a file entry which contains a command as the first
- entry. This function picks off the command from the file entry and passes
- the command back. }
-
- Begin { Command }
- ReturnFirstEntryFromString(Entry);
- Command:=Entry;
- End; { Command }
-
-
-
- Function NameEntry(FileEntry:FileEntryString):NameString;
-
- { This function is passed a file entry which contains a name as the second
- entry. This function picks off the name from the file entry and passes
- the name back. }
-
- Begin { NameEntry }
- RemoveFirstEntryFromString(FileEntry);
- ReturnFirstEntryFromString(FileEntry);
- NameEntry:=FileEntry;
- End; { NameEntry }
-
-
-
- Function BirthdateEntry(FileEntry:FileEntryString):BirthdateString;
-
- { This function is passed a file entry which contains a birthdate as the third
- entry. This function picks off the bithdate from the file entry and passes
- the birthdate back. }
-
- Begin { BirthdateEntry }
- RemoveFirstEntryFromString(FileEntry);
- RemoveFirstEntryFromString(FileEntry);
- ReturnFirstEntryFromString(FileEntry);
- BirthdateEntry:=FileEntry;
- End; { BirthdateEntry }
-
-
-
- Function AddressEntry(FileEntry:FileEntryString):AddressString;
-
- { This function is passed a file entry which contains a address as the fourth
- entry. This function picks off the address from the file entry and passes
- the address back. }
-
- Begin { AddressEntry }
- RemoveFirstEntryFromString(FileEntry);
- RemoveFirstEntryFromString(FileEntry);
- RemoveFirstEntryFromString(FileEntry);
- AddressEntry:=FileEntry;
- End; { AddressEntry }
-
-
-
- Function HashValue(PersonName:NameString):IndexType;
-
- { This function determines a hash table value for the passed PersonName. This
- function does this by first adding up the ASCII values of all the characters
- in the passed PersonName. It then determines a hash table value between 0
- and MAX_TABLE_SIZE by applying the Mod function to the accumulated ASCII
- value. }
-
- Var
- CharNumber:Integer;
- ASCIIvalue:Integer;
-
- Begin { HashValue }
- ASCIIvalue:=0; { initialize accumulator }
- For CharNumber:=1 To Length(PersonName) Do
- ASCIIvalue:=ASCIIvalue+Ord(Copy(PersonName,CharNumber,1));
- HashValue:=ASCIIvalue Mod (MAX_TABLE_SIZE+1);
- End; { HashValue }
-
-
-
- Procedure PrintQueryRecord(PersonDataRecord:Person);
-
- { This procedure prints the contents of the passed record that was
- searched for and found. }
-
- Begin { PrintQueryRecord }
- WriteLn;
- WriteLn('Record information about name searched for:');
- With PersonDataRecord Do
- Begin
- WriteLn(' Name : ',Name);
- WriteLn(' Birthdate : ',Birthdate);
- WriteLn(' Address : ',Address);
- End; { With PersonDataRecord }
- End; { PrintQueryRecord }
-
-
-
- Procedure PrintHashTableContents;
-
- { This procedure prints out the hash table and its contents. }
-
- Var
- Index:IndexType;
- CurrentPerson:Ptr; { a temporary pointer used in traversing the linked list }
-
- Begin { PrintHashTableContents }
- WriteLn;WriteLn;
- WriteLn;WriteLn;
- WriteLn(' HASH TABLE CONTENTS');
- WriteLn;
- WriteLn('Table Index Names hashing to this index');
- For Index:=0 To MAX_TABLE_SIZE Do
- Begin
- WriteLn;
- Write(' ',Index);
- If HashPtrTable[Index]=Nil Then
- WriteLn(' No entries')
- Else
- Begin
- If Index<10 Then
- WriteLn(' ',HashPtrTable[Index]^.Name)
- Else
- WriteLn(' ',HashPtrTable[Index]^.Name);
- CurrentPerson:=HashPtrTable[Index];
- While CurrentPerson^.Next<> Nil Do
- Begin
- CurrentPerson:=CurrentPerson^.Next;
- WriteLn(' ',CurrentPerson^.Name);
- End; { While CurrentPerson^.Next }
- End; { Else }
- End; { For Index }
- End; { PrintHashTableContents }
-
-
-
- Procedure InsertRecord(Entry:FileEntryString);
-
- { This procedure inserts a data record into one of the hash table's linked
- lists maintaining ascending sorted order according to name. Note that there
- are four special cases for inserting a record into the linked list:
-
- 1. No linked list present and thus must start linked list.
- 2. Insert entry into front of the existing linked list.
- 3. Insert entry into the middle of the existing linked list.
- 4. Insert entry at the end of the existing linked list. }
-
- Var
- CurrentPerson:Ptr; { a temporary pointer used in traversing the linked list }
- PreviousPerson:Ptr; { a temporary pointer used in traversing the linked list }
- NewPerson:Ptr; { a pointer to record type person whose record stores the new data entry }
- Index:IndexType;
- Done:Boolean; { a boolean used to tell the procedure when it has successfully inserted
- the data record }
-
- Begin { InsertRecord }
- WriteLn;
- WriteLn('Inserting a data entry into the data set.');
- New(NewPerson); {Create a new record to temporarily store the new entry }
- With NewPerson^ Do
- Begin { routine to enter information about new person }
- Name:=NameEntry(Entry);
- Birthdate:=BirthdateEntry(Entry);
- Address:=AddressEntry(Entry);
- Next:=Nil; { set next record pointer to Nil }
- WriteLn(' Name : ',Name);
- WriteLn(' Birthdate : ',Birthdate);
- WriteLn(' Address : ',Address);
- Index:=HashValue(Name); { determine hash table index value }
- End; { With NewPerson }
- { Special Case One - Check for the existance of linked list and if not existant, then start one with NewPerson }
- If HashPtrTable[Index]=Nil Then
- HashPtrTable[Index]:=NewPerson { no collision - start new linked list }
- Else
- Begin { collision occured }
- CurrentPerson:=HashPtrTable[Index];
- { Special Case Two - Check if NewPerson has to be inserted at the start of the linked list }
- If CurrentPerson^.Name>NewPerson^.Name Then
- Begin { insert NewPerson at the start of the linked list }
- HashPtrTable[Index]:=NewPerson; { have the hash table pointer point to NewPerson as the start of the linked list }
- NewPerson^.Next:=CurrentPerson; { have NewPerson point to previous head of the list }
- End { If CurrentPerson^.Name }
- Else
- Begin
- PreviousPerson:=CurrentPerson;
- Done:=False;
- While (CurrentPerson^.Next<>Nil) And Not Done Do
- { Special Case Three - Insert entry into the middle of the linked list }
- If (PreviousPerson^.Name<NewPerson^.Name) And (NewPerson^.Name<CurrentPerson^.Name) Then
- Begin { insert NewPerson into the middle of the linked list }
- PreviousPerson^.Next:=NewPerson; { set previous person pointer to point to NewPerson }
- NewPerson^.Next:=CurrentPerson; { set NewPerson to point to current person }
- Done:=True;
- PrintHashTableContents;
- End { If CurrentPerson^.Name }
- Else
- Begin { Increment pointers to traverse to next link in linked list }
- PreviousPerson:=CurrentPerson;
- CurrentPerson:=CurrentPerson^.Next;
- End; { Else }
- If Not Done Then
- { Special Case Four - Insert entry at end of linked list }
- If (PreviousPerson^.Name<NewPerson^.Name) And (NewPerson^.Name<CurrentPerson^.Name) Then
- Begin { insert NewPerson into the second to last position in linked list }
- PreviousPerson^.Next:=NewPerson; { set previous person pointer to point to NewPerson }
- NewPerson^.Next:=CurrentPerson; { set NewPerson to point to current person }
- End { If (PreviousPerson^.Name }
- Else
- CurrentPerson^.Next:=NewPerson;
- End; { Else }
- End; { Else }
- WriteLn;
- WriteLn('The data entry ',NewPerson^.Name,' was entered into the data set.');
- End; { InsertRecord }
-
-
-
- Procedure DeleteRecord(Entry:FileEntryString);
-
- { This procedure deletes a particular data record from the hash table's
- linked lists, while maintaining ascending sorted order according
- to name. Note that there are five special cases for inserting into the
- linked list:
-
- 1. No linked list present and thus no prior record entry.
- 2. Delete entry from front of the linked list.
- 3. Delete entry from the middle of the linked list.
- 4. Delete entry from the end of the linked list.
- 5. Record entry was not found.
-
- It is important to note that this procedure saves search time by only
- traversing through the linked list until it has reached an entry larger than
- the entry it is looking to delete. It then prints out that the entry was not
- able to be deleted since it was not found. }
-
- Var
- CurrentPerson:Ptr; { a temporary pointer used in traversing the linked list }
- PreviousPerson:Ptr; { a temporary pointer used in traversing the linked list }
- PersonToDelete:NameString; { a string to store person name used to find record to delete }
- Index:IndexType;
- Found:Boolean; { a boolean used to tell procedure when it has successfully found and
- deleted a data record }
- Quit:Boolean; { a boolean used to tell the procedure to stop looking for the record
- element due to ascending sorted order of the elements }
-
- Begin { DeleteRecord }
- { Routine to enter name so that proper record will be deleted from data set }
- WriteLn;
- WriteLn('Deleting a data entry from the data set.');
- PersonToDelete:=NameEntry(Entry);
- WriteLn(' Name : ',PersonToDelete);
- Index:=HashValue(PersonToDelete); { determine hash table index value }
- { Special Case One - Check for the existance of linked list and if not existant then print entry to delete not found }
- If HashPtrTable[Index]=Nil Then
- Begin { no collision-entry not found }
- WriteLn;
- WriteLn('The data entry ',PersonToDelete,' was not found in data set.');
- End { If HashPtrTable[Index] }
- Else
- Begin { collision occured }
- CurrentPerson:=HashPtrTable[Index];
- { Special Case Two - Check if PersonToDelete has to be deleted from the front of the linked list }
- If CurrentPerson^.Name=PersonToDelete Then
- Begin { delete person from the front of the linked list }
- If CurrentPerson^.Next<>Nil Then { determine if there exists a linked list extending beyond first entry }
- HashPtrTable[Index]:=CurrentPerson^.Next
- Else
- HashPtrTable[Index]:=Nil; { reset pointer since linked list is now gone }
- WriteLn;
- WriteLn('The data entry ',PersonToDelete,' was deleted from the data set.');
- Dispose(CurrentPerson); {Delete personRecord }
- End { If CurrentPerson^.Name }
- Else
- Begin
- PreviousPerson:=CurrentPerson;
- Quit:=False;
- Found:=False;
- While(CurrentPerson^.Next<>Nil) And Not Found And Not Quit Do
- Begin
- { Special Case Three - Delete from middle of linked list }
- If PersonToDelete<CurrentPerson^.Name Then
- Quit:=True;
- If CurrentPerson^.Name=PersonToDelete Then
- Begin { delete current person from middle of linked list }
- PreviousPerson^.Next:=CurrentPerson^.Next; { set previous person pointer to point to next person }
- WriteLn;
- WriteLn('The data entry ',PersonToDelete,' was deleted from the data set.');
- Dispose(CurrentPerson); { delete person record }
- Found:=True;
- End { If CurrentPerson^.Name }
- Else
- Begin { increment pointer to traverse to next link of linked list }
- PreviousPerson:=CurrentPerson;
- CurrentPerson:=CurrentPerson^.Next;
- End; { Else }
- End; { While CurrentPerson^.Next }
- If Not Found And (CurrentPerson^.Name=PersonToDelete) Then
- { Special Case Four - Delete name from end of linked list }
- Begin
- PreviousPerson^.Next:=Nil;
- WriteLn;
- WriteLn('The data entry ',PersonToDelete,' was deleted from the data set.');
- Dispose(CurrentPerson);
- End { If Not Found }
- Else
- If Not Found Then
- { Special Case Five - No entry was found }
- Begin
- WriteLn;
- WriteLn('The data entry ',PersonToDelete,' was not found in the data set.');
- End; { If Not Found }
- End; { Else }
- End; { Else }
- End; { DeleteRecord }
-
-
-
- Procedure SearchForRecord(Entry:FileEntryString);
-
- { This procedure searches for a particular data record according to the name
- field from the hash table's linked lists. It then passes the found record
- to the procedure PrintQueryRecord to be printed. Note that there are five
- special cases for searching a linked list for a particular entry:
-
- 1. No linked list present and thus no prior entry.
- 2. Record entry found at front of the linked list.
- 3. Record entry found in the middle of the linked list.
- 4. Record entry found at the end of the linked list.
- 5. Record entry was not found.
-
- It is important to note that this procedure saves search time by only
- traversing through the linked list until it has reached an entry larger than
- the entry it is searching for. It then prints out that the entry was not
- found. }
-
- Var
- CurrentPerson:Ptr; { a temporary pointer used in traversing the linked list }
- QueryPerson:NameString; { a string used to temporarily store the name whose record is
- being searched for }
- Index:IndexType;
- Found:Boolean; { a boolean used to tell the procedure when it has successfully found and
- printed the queried data record }
- Quit:Boolean; { a boolean used to tell the procedure to stop looking for the record
- element due to ascending sorted order of the elements }
-
- Begin { SearchForRecord }
- { routine to enter name so that proper record will be found in data set }
- WriteLn;
- WriteLn('Searching for a data entry in the data set.');
- QueryPerson:=NameEntry(Entry);
- WriteLn(' Name : ',QueryPerson);
- Index:=HashValue(QueryPerson); { determine hash table index value }
- { Special Case One - Check for the existance of linked list and if not existant then print entry to find not found }
- If HashPtrTable[Index]=Nil Then
- Begin { no collision-query person not found }
- WriteLn;
- WriteLn('The data entry ',QueryPerson,' was not found in the data set.');
- End { If HashPtrTable[Index] }
- Else
- Begin { collision occured }
- CurrentPerson:=HashPtrTable[Index];
- { Special Case Two - Check if query person is at the front of the linked list }
- If CurrentPerson^.Name=QueryPerson Then
- PrintQueryRecord(CurrentPerson^)
- Else
- Begin
- Quit:=False;
- Found:=False;
- While (CurrentPerson^.Next<>Nil) And Not Found And Not Quit Do
- { Special Case Three - Check if query person in middle of linked list }
- Begin
- If QueryPerson<CurrentPerson^.Name Then
- Quit:=True;
- If CurrentPerson^.Name=QueryPerson Then
- Begin { query person found-print data record }
- PrintQueryRecord(CurrentPerson^);
- Found:=True;
- End { If CurrentPerson^.Name }
- Else
- Begin { increment pointer to traverse to next link of the linked list }
- CurrentPerson:=CurrentPerson^.Next;
- End; { Else }
- End; { While CurrentPerson^.Next }
- If Not Found And (CurrentPerson^.Name=QueryPerson) Then
- { Special Case Four - Query name at the end of the linked list }
- PrintQueryRecord(CurrentPerson^)
- Else
- { Special Case Five - No entry was found }
- Begin
- WriteLn;
- WriteLn('The data entry ',QueryPerson,' was not found in the data set');
- End; { Else }
- End; { Else }
- End; { Else }
- End; { SearchForRecord }
-
-
-
- Procedure ReadInputFile;
-
- { This procedure begins by first reading the entry in the declared file. The
- file entry is in the form
-
- Command Name Birthdate Address
-
- The procedure then determines the command that is contained in the file
- entry. Possible commands are:
-
- 'I' Insert a record into the data set
- 'D' Delete a record from the data set
- 'S' Search for a record in data set and print out contents
-
- This procedure then passes control to the specific procedure called.
- If none of the above commands were entered in the file entry, the procedure
- prints an error message stating that a bad command was entered. }
-
- Var
- DataFile:Text; { Text File }
- FileEntry:FileEntryString;
- CommandEntry:FileEntryString;
-
- Begin { ReadInputFile }
- Assign(DataFile,FILE_NAME); { assign to a disk file }
- Reset(DataFile); { open the file for reading }
- Repeat { read in the file entries }
- ReadLn(DataFile,FileEntry);
- WriteLn;
- WriteLn;
- WriteLn;
- WriteLn;
- WriteLn('File Entry = ',FileEntry);
- CommandEntry:=Command(FileEntry);
- WriteLn;
- WriteLn('Command = ',CommandEntry);
- Case CommandEntry Of { pass control to specific procedure }
- 'I' : InsertRecord(FileEntry);
- 'D' : DeleteRecord(FileEntry);
- 'S' : SearchForRecord(FileEntry);
- Else { improper command encountered }
- WriteLn;
- WriteLn('Bad command was found in the following file entry:');
- WriteLn(' ',FileEntry);
- End; { Case Command(FileEntry) }
- Until Eof(DataFile);
- Close(DataFile); { close the disk file }
- End; { ReadInputFile }
-
-
-
- Begin { Main Program }
- HoldPtr:=ConOutPtr; { temporarily store current output address }
- If L_PRINT Then
- ConOutPtr:=LstOutPtr; { re-direct output to the printer }
- PrintHeading;
- InitHashTable;
- ReadInputFile;
- PrintHashTableContents;
- ConOutPtr:=HoldPtr; { reset output device address }
- End. { Main Program }
-
-